home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / Thread Manager / Sample Applications / 68k Examples / Single Intersection Threads / USimulation.p < prev   
Encoding:
Text File  |  1994-11-17  |  52.5 KB  |  1,417 lines  |  [TEXT/MPS ]

  1. {–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
  2.  
  3.     PROJECT:        Threads Traffic Simulation
  4.     
  5.     FILE:            USimulation.p
  6.     
  7.     LANGUAGE:        MPW Pascal (version 3.2)
  8.         
  9.     DESCRIPTION:    This is where all the magic happens.  Initially after the document is
  10.                     initialized four threads are started up, two to control the street light,
  11.                     one to keep a time global up to date for pre-emptive threads, and one to
  12.                     continually look for two free threads, one that is pre-emptive and one that
  13.                     is cooperative, with which it can create a new car.
  14.         
  15.     AUTHOR(S):        William H. Knott
  16.                     Apple Computer
  17.                     Cupertino, CA  95014
  18.                     AppleLink : KNOTT
  19.     
  20.     VERSION(S):        1.0        20-Jul-92    WHK    First rev Finished today.
  21.  
  22. –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––}
  23.  
  24. UNIT USimulation;
  25.  
  26. INTERFACE
  27.  
  28. USES
  29.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps, 
  30.     
  31.     Threads,
  32.     
  33.     UApplication, UInitMgmt, UDocument;
  34.  
  35. PROCEDURE Segment_UTestSuite;
  36.  
  37. PROCEDURE InitializeRoadParams;
  38. PROCEDURE CreateTrafficLight;
  39. PROCEDURE DrawTheTraficLight(fromThread    : BOOLEAN);
  40. PROCEDURE CreateFreeThreadsForCars;
  41. PROCEDURE UpdateAllCars;
  42. PROCEDURE MarkACarForDestruction;
  43.  
  44. CONST
  45.     kMedianSize            = 80;
  46.     
  47.     kMaxNumOfThreads    = 15;
  48.     kCarJumpRatio        = 5;
  49.     
  50.     kCarLength            = 15;
  51.     kCarWidth            = 4;
  52.  
  53.     kRoadWidth            = 60;
  54.     HellFreezesOver        = FALSE;
  55.     
  56. VAR
  57.     gTotalCarsInArray    : INTEGER;
  58.     
  59.     gVRoadLeft            : INTEGER;
  60.     gVRoadRight            : INTEGER;
  61.     gVRoadTop            : INTEGER;
  62.     gVRoadBottom        : INTEGER;
  63.  
  64.     gHRoadLeft            : INTEGER;
  65.     gHRoadRight            : INTEGER;
  66.     gHRoadTop            : INTEGER;
  67.     gHRoadBottom        : INTEGER;
  68.     
  69.     gA5Check            : INTEGER;
  70.  
  71. IMPLEMENTATION
  72.  
  73. PROCEDURE InitializeRoadParams;
  74.     VAR
  75.         roadTemp    : INTEGER;
  76.     BEGIN
  77.         gTotalCarsInArray := 0;
  78.         
  79.         roadTemp := (gWindowSize.right - gWindowSize.left) DIV 2 - (kRoadWidth DIV 2);
  80.         gVRoadLeft := roadTemp;
  81.         gVRoadRight := roadTemp + kRoadWidth;
  82.         gVRoadTop := gWindowSize.top;
  83.         gVRoadBottom := gWindowSize.bottom;
  84.     
  85.         roadTemp := (gWindowSize.bottom - gWindowSize.top) DIV 2 - (kRoadWidth DIV 2);
  86.         gHRoadLeft := gWindowSize.left;
  87.         gHRoadRight := gWindowSize.right;
  88.         gHRoadTop := roadTemp;
  89.         gHRoadBottom := roadTemp + kRoadWidth;
  90.     END;
  91.  
  92. PROCEDURE CreateCarGeneratingThread;
  93.     FORWARD;
  94.  
  95. {$S Simulation}
  96. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  97. {                                                                                      }
  98. {    Segment_UDocument                                                                  }
  99. {                                                                                      }
  100. {    Provided as a convenient way of unloading the UDocument segment when needed          }
  101. {                                                                                      }
  102. {    July 15, 1992        WHK        Created today                                          }
  103. {                                                                                      }
  104. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  105. PROCEDURE Segment_UTestSuite;
  106.     BEGIN
  107.     END;
  108.  
  109. {$S Simulation}
  110. {–––––––––––––––––––––––––––––COOPERATIVE & PREEMPTIVE–––––––––––––––––––––––––––––-––}
  111. {                                                                                      }
  112. {    ReturnCarHandle                                                                      }
  113. {                                                                                      }
  114. {    Return a AutoHandle to the car with the given carID.  If no such carID exists,      }
  115. {    return NIL                                                                          }
  116. {                                                                                      }
  117. {    July 15, 1992        WHK        Created today                                          }
  118. {                                                                                      }
  119. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  120. FUNCTION ReturnCarHandle(theCarID    : INTEGER)    : AutoHandle;
  121.     BEGIN
  122.         ReturnCarHandle := NIL;
  123.         IF gAutomobiles = NIL THEN EXIT(ReturnCarHandle);
  124.         IF gTotalCarsInArray < theCarID THEN
  125.             BEGIN
  126.                 DebugStr('Index is out of range');
  127.                 EXIT(ReturnCarHandle)
  128.             END;
  129.         ReturnCarHandle := gAutomobiles^^[theCarID];
  130.     END;
  131.  
  132. {$S Simulation}
  133. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  134. {                                                                                      }
  135. {    DoesCarExist                                                                      }
  136. {                                                                                      }
  137. {    Does a car with that ID number exist in our current world of cars.  Try to get      }
  138. {    its handle,     and if successful, then return TRUE, else FALSE.                      }
  139. {                                                                                      }
  140. {    July 15, 1992        WHK        Created today                                          }
  141. {                                                                                      }
  142. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  143. FUNCTION DoesCarExist(theCarID    : INTEGER)    : BOOLEAN;
  144.     VAR
  145.         theCar    : AutoHandle;
  146.     BEGIN
  147.         theCar := ReturnCarHandle(theCarID);
  148.         DoesCarExist := NOT (theCar = NIL);
  149.     END;
  150.  
  151. {$S Simulation}
  152. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  153. {                                                                                      }
  154. {    GetUniqueCarID                                                                      }
  155. {                                                                                      }
  156. {    Keep generating a new number and seeing if it exists. Once it does not, return      }
  157. {    that number                                                                           }
  158. {                                                                                      }
  159. {    July 15, 1992        WHK        Created today                                          }
  160. {                                                                                      }
  161. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  162. FUNCTION GetUniqueCarID    : INTEGER;
  163.     VAR
  164.         startCount    : INTEGER;
  165.         newCar        : INTEGER;
  166.     BEGIN
  167.         newCar := 0;
  168.         
  169.         IF gTotalCarsInArray= 0 THEN
  170.             BEGIN
  171.                 GetUniqueCarID := 1;
  172.                 EXIT(GetUniqueCarID);
  173.             END;
  174.         
  175.         FOR startCount := 1 TO gTotalCarsInArray DO
  176.             BEGIN
  177.                 IF NOT DoesCarExist(startCount) THEN
  178.                     newCar := startCount;
  179.             END;
  180.         
  181.         IF newCar = 0 THEN
  182.             GetUniqueCarID := gTotalCarsInArray + 1
  183.         ELSE
  184.             GetUniqueCarID := newCar;
  185.     END;
  186.  
  187. {$S Simulation}
  188. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  189. {                                                                                      }
  190. {    GetStartingCarPointAndLocation                                                      }
  191. {                                                                                      }
  192. {    Getting a startign point for a new car.  There are only four valid starting          }
  193. {    points for now.                                                                      }
  194. {                                                                                      }
  195. {    July 15, 1992        WHK        Created today                                          }
  196. {                                                                                      }
  197. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  198. PROCEDURE  GetStartingCarPointAndLocation(VAR position    : POINT;
  199.                                             VAR direction    : INTEGER);
  200.     BEGIN
  201.         direction := (abs(Random) MOD 4) * 90;
  202.         CASE direction OF
  203.             0:        SetPt(position, gHRoadLeft + 3, gHRoadBottom - 8);
  204.             90:        SetPt(position, gVRoadRight - 8, gVRoadBottom);
  205.             180:    SetPt(position, gHRoadRight, gHRoadTop + 9);
  206.             270:    SetPt(position, gVRoadLeft + 8, gVRoadTop);
  207.             OTHERWISE
  208.                 BEGIN
  209.                     direction := 0;
  210.                     SetPt(position, gHRoadLeft + 3, gHRoadBottom - 8);
  211.                 END;
  212.         END;
  213.     END;
  214.     
  215. {$S Simulation}
  216. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  217. {                                                                                      }
  218. {    AddAutoMobileToList                                                                   }
  219. {                                                                                      }
  220. {    Add a new car handle to the list of all the cars on the road.  Dynamic array is      }
  221. {    used to store all of the cars.                                                      }
  222. {                                                                                      }
  223. {    July 15, 1992        WHK        Created today                                          }
  224. {                                                                                      }
  225. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  226. PROCEDURE AddAutoMobileToList(newRefNum    : INTEGER;
  227.                                 aCar    : AutoHandle);
  228.     VAR
  229.         error    : OSErr;
  230.     BEGIN
  231.         IF gAutomobiles = NIL THEN
  232.             gAutomobiles := AutoListArrayHdl(NewHandleClear(SizeOf(Handle)));
  233.         
  234.         error := ThreadBeginCritical;        { This is a global used by other threads and could move, so prevent others from using it } 
  235.             IF (GetHandleSize(Handle(gAutomobiles)) DIV SizeOF(Handle)) < newRefNum THEN
  236.                     SetHandleSize(Handle(gAutomobiles), newRefNum * SizeOf(Handle));
  237.             IF MemError <> noErr THEN
  238.                 DebugSTr('Inadequate memory');
  239.                 
  240.             gAutomobiles^^[newRefNum] := aCar;
  241.             
  242.             gTotalCarsInArray := GetHandleSize(Handle(gAutomobiles)) DIV 4;
  243.         error := ThreadEndCritical;            { OK, done my stuff with the handle, others can use it now.    }
  244.         
  245.     END;
  246.  
  247. {$S Simulation}
  248. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  249. {                                                                                      }
  250. {    CreateANewAutomobile                                                              }
  251. {                                                                                      }
  252. {    Creates a new automobile in the car list.  Parameters like direction and car      }
  253. {    color are random, everything else is fixed for all cars.                          }
  254. {                                                                                      }
  255. {    July 15, 1992        WHK        Created today                                          }
  256. {                                                                                      }
  257. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  258. PROCEDURE CreateANewAutomobile(newRefNum    : INTEGER);
  259.     VAR
  260.         aCar    : AutoHandle;
  261.     BEGIN
  262.         aCar := AutoHandle(NewHandleClear(SizeOf(AutoRec)));
  263.         MoveHHi(Handle(aCar));
  264.         HLock(Handle(aCar));                            { Car cannot move in memory of Async threads could get screwed!            }
  265.         WITH aCar^^ DO
  266.             BEGIN
  267.                 GetStartingCarPointAndLocation(position, direction);
  268.                 carType := (abs(RANDOM) MOD 5);            { Right now only means the color of the car.                            }
  269.                 speed := 40;                            { Only 40 or zero currently, not much in way of variance for first run.    }
  270.                 accelleration := 1;                        { Only 1, way too complex for first time around.                        }
  271.                 braking := 1;                            { Only 1, way too complex for first time around.                        }
  272.                 needToRedraw := TRUE;                    { First Time, definate draw needed                                        }
  273.                 carIsDone := FALSE;                        { Car is still on the map!                                                }
  274.                 recalcCarShape := FALSE;                { Only needed when a car has turned                                        }
  275.                 markedForDeath := FALSE;                { We do not want to destroy the car.                                    }
  276.                 oldTrapAddr := NIL;                        { Initialize to NIL so switcher outer does not do bad things.            }
  277.                 
  278.                 IF (Random MOD 10) IN [0,1] THEN
  279.                     turning := TRUE
  280.                 ELSE
  281.                     turning := FALSE;
  282.             END;
  283.         
  284.         AddAutoMobileToList(newRefNum, aCar);
  285.     END;
  286.  
  287. {$S Simulation}
  288. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  289. {                                                                                      }
  290. {    CarDrawingThread                                                                  }
  291. {                                                                                      }
  292. {    As the car moves along the road, we need to draw its new position and erase          }
  293. {    its old one.  This code does just that, and continues to draw the car until a      }
  294. {    variable is set by the pre-emptive thread telling it to dispose of itself.          }
  295. {                                                                                      }
  296. {    July 15, 1992        WHK        Created today                                          }
  297. {                                                                                      }
  298. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  299. FUNCTION CarDrawingThread(theCarRefID    : LONGINT)    : LONGINT;
  300.     VAR
  301.         theCar            : AutoHandle;
  302.  
  303.         error            : OSErr;
  304.         oldCarLoc        : POINT;
  305.         notFirstTime    : BOOLEAN;
  306.         carRect            : RECT;
  307.         direction        : INTEGER;
  308.         carIsErased        : BOOLEAN;
  309.         myThreadID        : ThreadID;
  310.         markedForDeath    : BOOLEAN;
  311.     BEGIN
  312.         theCar := ReturnCarHandle(theCarRefID);
  313.         SetPt(oldCarLoc, -1, -1);
  314.         direction := theCar^^.direction;
  315.         
  316.         carIsErased := FALSE;
  317.         
  318.         IF theCar = NIL THEN
  319.             DebugStr('Bogus, no such car')
  320.         ELSE
  321.             BEGIN
  322.                 notFirstTime := FALSE;
  323.                 repeat
  324.                     IF theCar^^.needToRedraw THEN    { We need to redraw the car!    }
  325.                         BEGIN
  326.                             error := ThreadBeginCritical;    { I do not want other threads to change car data while I am in the middle of drawing the car }
  327.                             SetPort(gDocument^^.docWindow);
  328.                             IF notFirstTime THEN
  329.                                 BEGIN
  330.                                     ForeColor(BlackColor);
  331.                                     IF direction IN [180,0] THEN
  332.                                         SetRect(carRect, oldCarLoc.h, oldCarLoc.v - kCarWidth, oldCarLoc.h + kCarLength, oldCarLoc.v + kCarWidth)
  333.                                     ELSE
  334.                                         SetRect(carRect, oldCarLoc.h - kCarWidth, oldCarLoc.v, oldCarLoc.h + kCarWidth, oldCarLoc.v + kCarLength);
  335.                                     FillRect(carRect, gray);
  336.                                 END
  337.                             ELSE
  338.                                 notFirstTime := TRUE;
  339.                             
  340.                             IF theCar^^.recalcCarShape THEN
  341.                                 BEGIN
  342.                                     direction := theCar^^.direction;
  343.                                     theCar^^.recalcCarShape := FALSE;
  344.                                 END;
  345.                             
  346.                             IF direction IN [180,0] THEN
  347.                                 SetRect(carRect, theCar^^.position.h, theCar^^.position.v - kCarWidth,
  348.                                                 theCar^^.position.h + kCarLength, theCar^^.position.v + kCarWidth)
  349.                             ELSE
  350.                                 SetRect(carRect, theCar^^.position.h - kCarWidth, theCar^^.position.v,
  351.                                                 theCar^^.position.h + kCarWidth, theCar^^.position.v + kCarLength);
  352.                             
  353.                             CASE theCar^^.carType  OF
  354.                                 1:    ForeColor(kColorOne);
  355.                                 2:    ForeColor(kColorTwo);
  356.                                 3:    ForeColor(kColorThree);
  357.                                 4:    ForeColor(kColorFour);
  358.                                 OTHERWISE
  359.                                         ForeColor(YellowColor);
  360.                             END;
  361.                             IF theCar^^.carType = 5 THEN ForeColor(WhiteColor);
  362.                             
  363.                             FillRect(carRect, black);
  364.                             ForeColor(BlackColor);
  365.                             oldCarLoc := theCar^^.position;
  366.                             
  367.                             theCar^^.needToRedraw := FALSE;
  368.  
  369.                             error := ThreadEndCritical;    { Done drawing the car, let others change away.    }
  370.                         END;
  371.                     error := YieldToAnyThread;    { Give the other cooperative threads time to do their drawing and handle events.    }                    
  372.                 until theCar^^.carIsDone;
  373.                 
  374.                 SetPort(gDocument^^.docWindow);
  375.                 ForeColor(BlackColor);
  376.                 IF direction IN [180,0] THEN
  377.                     SetRect(carRect, oldCarLoc.h, oldCarLoc.v - kCarWidth, oldCarLoc.h + kCarLength, oldCarLoc.v + kCarWidth)
  378.                 ELSE
  379.                     SetRect(carRect, oldCarLoc.h - kCarWidth, oldCarLoc.v, oldCarLoc.h + kCarWidth, oldCarLoc.v + kCarLength);
  380.  
  381.                 FillRect(carRect, gray);
  382.             END;
  383.         
  384.         markedForDeath := theCar^^.markedForDeath;
  385.         DisposHandle(Handle(gAutomobiles^^[theCarRefID]));
  386.         gAutomobiles^^[theCarRefID] := NIL;
  387.         
  388.         error := GetCurrentThread(myThreadID);                { I wish to recycle this thread(possibly), so I need to know my own ID.    }
  389.         IF markedForDeath THEN
  390.             error := DisposeThread(myThreadID, 0, FALSE)    { Dispose of myself, do not recycle the threaed into the thread pool.    }    
  391.         ELSE
  392.             error := DisposeThread(myThreadID, 0, TRUE);    { Dispose of myself, recycle the threaed into the thread pool.    }
  393.     END;
  394.  
  395. {$S Simulation}
  396. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  397. {                                                                                      }
  398. {    UpdateAllCars                                                                      }
  399. {                                                                                      }
  400. {    Something could cause an update of our simulated world,and if a car is not          }
  401. {    moving, it would dissapear  until it began to move again.  Lets fix it so that      }
  402. {    all the cars will be updated on an update event.                                  }
  403. {                                                                                      }
  404. {    July 15, 1992        WHK        Created today                                          }
  405. {                                                                                      }
  406. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  407. PROCEDURE UpdateAllCars;
  408.     VAR
  409.         hndlSize    : LONGINT;
  410.         numOfCars    : INTEGER;
  411.         loop        : INTEGER;
  412.         theCar        : AutoHandle;
  413.     BEGIN
  414.         IF gAutomobiles = NIL THEN EXIT(UpdateAllCars);
  415.         hndlSize := GetHandleSize(Handle(gAutomobiles));
  416.         numOfCars := LoWord(hndlSize) DIV 4;
  417.         
  418.         FOR loop := 1 TO numOfCars DO
  419.             BEGIN
  420.                 theCar := ReturnCarHandle(loop);
  421.                 IF theCar <> NIL THEN
  422.                     BEGIN
  423.                         theCar^^.needToRedraw := TRUE;
  424.                     END;
  425.             END;
  426.     END;
  427.  
  428. {$S Simulation}
  429. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  430. {                                                                                      }
  431. {    CarLeavesPlayingField                                                              }
  432. {                                                                                      }
  433. {    Cars would continue to go forever after they left the playing field if we did      }
  434. {    not deter mine when if left the window so that we could re-use its thread.           }
  435. {                                                                                      }
  436. {    July 15, 1992        WHK        Created today                                          }
  437. {                                                                                      }
  438. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  439. FUNCTION CarLeavesPlayingField(carLoc    : POINT)    : BOOLEAN;
  440.     BEGIN
  441.         CarLeavesPlayingField := TRUE;
  442.         IF gWindowSize.left > (carLoc.h + kCarLength) THEN EXIT(CarLeavesPlayingField);
  443.         IF gWindowSize.right < (carLoc.h) THEN EXIT(CarLeavesPlayingField);
  444.         IF gWindowSize.top > (carLoc.v + kCarLength) THEN EXIT(CarLeavesPlayingField);
  445.         IF gWindowSize.bottom < (carLoc.v) THEN EXIT(CarLeavesPlayingField);
  446.         CarLeavesPlayingField := FALSE;
  447.     END;
  448.  
  449. {$S Simulation}
  450. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  451. {                                                                                      }
  452. {    AmIAtIntersection                                                                  }
  453. {                                                                                      }
  454. {    Well, am I even at the intersection.  The car calculation needs to handle things  }
  455. {    differently when we are in the intersection.  This will let me know whether we      }
  456. {    have entered the intersection or not.                                              }
  457. {                                                                                      }
  458. {    July 15, 1992        WHK        Created today                                          }
  459. {                                                                                      }
  460. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  461. FUNCTION AmIAtIntersection(carDir    : INTEGER;
  462.                             carLoc    : POINT)    : BOOLEAN;
  463.     VAR
  464.         disToLight    : INTEGER;
  465.     BEGIN
  466.         CASE carDir OF
  467.             0:        disToLight :=  abs(gVRoadLeft - (carLoc.h + kCarLength));    { Car Size needs to be calculated!    }
  468.             90:        disToLight :=  abs(gHRoadBottom - carLoc.v);
  469.             180:    disToLight :=  abs(gVRoadRight - carLoc.h);
  470.             270:    disToLight :=  abs(gHRoadTop - (carLoc.v + kCarLength));
  471.         END;
  472.         AmIAtIntersection := (disToLight < (kCarJumpRatio + 1));
  473.     END;
  474.  
  475. {$S Simulation}
  476. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  477. {                                                                                      }
  478. {    IsLightRed                                                                          }
  479. {                                                                                      }
  480. {    Quick and dirty little routine to tell me whether the traffic light is red for      }
  481. {    the direction that I am going.                                                      }
  482. {                                                                                      }
  483. {    July 15, 1992        WHK        Created today                                          }
  484. {                                                                                      }
  485. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  486. FUNCTION IsLightRed(carDir    : INTEGER)    : BOOLEAN;
  487.     BEGIN
  488.         IsLightRed := FALSE;
  489.         IF (carDir = 0) | (carDir = 180) THEN
  490.             BEGIN
  491.                 IF gTrafficState.lightState IN [0,4,5,6,7] THEN
  492.                     IsLightRed := TRUE;
  493.             END
  494.         ELSE
  495.             BEGIN
  496.                 IF gTrafficState.lightState IN [0,1,2,3,4] THEN
  497.                     IsLightRed := TRUE;
  498.             END;
  499.     END;
  500.     
  501. {$S Simulation}
  502. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  503. {                                                                                      }
  504. {    IsLightGreen                                                                      }
  505. {                                                                                      }
  506. {    Quick and dirty little routine to tell me whether the traffic light is green      }
  507. {    for the the direction that I am going.                                              }
  508. {                                                                                      }
  509. {    July 15, 1992        WHK        Created today                                          }
  510. {                                                                                      }
  511. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  512. FUNCTION IsLightGreen(carDir    : INTEGER)    : BOOLEAN;
  513.     BEGIN
  514.         IsLightGreen := FALSE;
  515.         IF (carDir = 0) | (carDir = 180) THEN
  516.             BEGIN
  517.                 IF gTrafficState.lightState = 2 THEN
  518.                     IsLightGreen := TRUE;
  519.             END
  520.         ELSE
  521.             BEGIN
  522.                 IF gTrafficState.lightState = 6 THEN
  523.                     IsLightGreen := TRUE;
  524.             END;
  525.     END;
  526.     
  527. {$S Simulation}
  528. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  529. {                                                                                      }
  530. {    IsLightArrow                                                                      }
  531. {                                                                                      }
  532. {    Quick and dirty little routine to tell me whether the traffic light is a green      }
  533. {    arrow for the direction that I am going.                                          }
  534. {                                                                                      }
  535. {    July 15, 1992        WHK        Created today                                          }
  536. {                                                                                      }
  537. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  538. FUNCTION IsLightArrow(carDir    : INTEGER)    : BOOLEAN;
  539.     BEGIN
  540.         IsLightArrow := FALSE;
  541.         IF (carDir = 0) | (carDir = 180) THEN
  542.             BEGIN
  543.                 IF gTrafficState.lightState = 1 THEN
  544.                     IsLightArrow := TRUE;
  545.             END
  546.         ELSE
  547.             BEGIN
  548.                 IF gTrafficState.lightState = 5 THEN
  549.                     IsLightArrow := TRUE;
  550.             END;
  551.     END;
  552.     
  553. {$S Simulation}
  554. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  555. {                                                                                      }
  556. {    AmIOnTopOfACar                                                                       }
  557. {                                                                                      }
  558. {    When placing new cars onto the map, I need to see whether there is already a car  }
  559. {    in the position that I just placed a new car.  If there is, I had probably better }
  560. {    do something about it.                                                              }
  561. {                                                                                      }
  562. {    July 15, 1992        WHK        Created today                                          }
  563. {                                                                                      }
  564. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  565. FUNCTION AmIOnTopOfACar(carLoc    : POINT;
  566.                         carDir    : INTEGER;
  567.                         carID    : INTEGER)    : BOOLEAN;
  568.     VAR
  569.         loop                : INTEGER;
  570.         aCar                : AutoHandle;
  571.         distancebetweencars    : INTEGER;
  572.     BEGIN
  573.         AmIOnTopOfACar := FALSE;
  574.         FOR loop := 1 TO gTotalCarsInArray DO
  575.             BEGIN
  576.                 IF carID = loop THEN Cycle;
  577.                 aCar := ReturnCarHandle(loop);
  578.                 IF (aCar <> NIL) & (aCar^^.direction = carDir) THEN
  579.                     BEGIN
  580.                         IF (aCar^^.position.v = carLoc.v) AND (aCar^^.position.h = carLoc.h) THEN
  581.                                 AmIOnTopOfACar := TRUE;
  582.  
  583.                         distancebetweencars := abs(aCar^^.position.h - carLoc.h) + abs(aCar^^.position.v - carLoc.v) ;
  584.                         
  585.                         IF (distancebetweencars < (kCarLength * 2)) THEN
  586.                             AmIOnTopOfACar := TRUE;
  587.                     END;
  588.             END;
  589.     END;
  590.  
  591. {$S Simulation}
  592. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  593. {                                                                                      }
  594. {    IsThereACarStoppedInFrontOfMe                                                      }
  595. {                                                                                      }
  596. {    When this simulation was first coded, cars did not seem to realise that two of      }
  597. {    them could not occupy the same space at the same time.  This attempts to solve      }
  598. {    some of these problems by looking to see if there is a car in front of the          }
  599. {    current car and whether it is stopped or not.  If it is stopped, then we had      }
  600. {    better stop.                                                                      }
  601. {                                                                                      }
  602. {    July 15, 1992        WHK        Created today                                          }
  603. {                                                                                      }
  604. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  605. FUNCTION IsThereACarStoppedInFrontOfMe(carLoc    : POINT;
  606.                                         carDir    : INTEGER;
  607.                                         carID    : INTEGER)    : BOOLEAN;
  608.     VAR
  609.         loop                : INTEGER;
  610.         aCar                : AutoHandle;
  611.         distancebetweencars    : INTEGER;
  612.         onLine                : BOOLEAN;
  613.         error                : OSErr;
  614.     BEGIN
  615.         IsThereACarStoppedInFrontOfMe := FALSE;
  616.  
  617.         FOR loop := 1 TO gTotalCarsInArray DO
  618.             BEGIN
  619.                 IF carID = loop THEN Cycle;
  620.                 error := ThreadBeginCritical;    { Do not want other threads to move cars while I am trying to determine if there is a car in front of me.    }
  621.                 aCar := ReturnCarHandle(loop);
  622.                 
  623.                 IF (aCar <> NIL) & (aCar^^.direction = carDir) THEN
  624.                     BEGIN
  625.                         IF (aCar^^.position.v = carLoc.v) AND (aCar^^.position.h = carLoc.h) THEN
  626.                             BEGIN
  627.                                 
  628.                             END;
  629.                         IF aCar^^.speed = 0 THEN    { If this car is going our direction, and is stopped, we may need to stop!    }
  630.                             BEGIN
  631.                                 CASE aCar^^.direction OF
  632.                                     0:        distancebetweencars := aCar^^.position.h - carLoc.h;
  633.                                     90:        distancebetweencars := -(aCar^^.position.v - carLoc.v);
  634.                                     180:    distancebetweencars := -(aCar^^.position.h - carLoc.h);
  635.                                     270:    distancebetweencars := aCar^^.position.v - carLoc.v;
  636.                                 END;
  637.                                 
  638.                                 onLine := TRUE;
  639.                                 IF aCar^^.direction IN [0,180] THEN onLine := abs(aCar^^.position.v - carLoc.v) < 10;
  640.                                 IF aCar^^.direction IN [90, 270] THEN onLine := abs(aCar^^.position.h - carLoc.h) < 10;
  641.                                 
  642.                                 IF ((((kCarLength * 3) DIV 2) >= distancebetweencars) AND (distancebetweencars > 0)) AND onLine THEN
  643.                                     IsThereACarStoppedInFrontOfMe := TRUE;
  644.                             END;
  645.                     END;
  646.                 error := ThreadEndCritical;    { Done my determination, all cars are free to move again.    }
  647.             END;
  648.     END;
  649.  
  650. {$S Simulation}
  651. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  652. {                                                                                      }
  653. {    AmIAtLangeChangePoint                                                              }
  654. {                                                                                      }
  655. {    If I am a car that is planning to turn left, I need to see whether I am at the       }
  656. {    point where I need to start moving into the left hand turn lane.                   }
  657. {                                                                                      }
  658. {    July 15, 1992        WHK        Created today                                          }
  659. {                                                                                      }
  660. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  661. FUNCTION AmIAtLangeChangePoint(carID        : INTEGER)    : BOOLEAN;
  662.     VAR
  663.         aCar            : AutoHandle;
  664.         turningPoint    : BOOLEAN;
  665.     BEGIN
  666.         AmIAtLangeChangePoint := FALSE;
  667.         aCar := ReturnCarHandle(carID);
  668.         CASE aCar^^.direction OF
  669.             0:        turningPoint := (aCar^^.position.h >= gVRoadLeft - kMedianSize);
  670.             90:        turningPoint := (aCar^^.position.v <= gHRoadBottom + kMedianSize);
  671.             180:    turningPoint := (aCar^^.position.h <= gVRoadRight + kMedianSize);
  672.             270:    turningPoint := (aCar^^.position.v >= gHRoadTop - kMedianSize);
  673.         END;
  674.         AmIAtLangeChangePoint := turningPoint;
  675.     END;
  676.  
  677. {$S Simulation}
  678. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  679. {                                                                                      }
  680. {    AmIAtTurnPoint                                                                      }
  681. {                                                                                      }
  682. {    This should be made more flexible, but for now the simulation only has a single      }
  683. {    intersection.  Lets me know whether my car is at a point at which I need to turn  }
  684. {    left.  Right turns have not yet been implemented.                                  }
  685. {                                                                                      }
  686. {    July 15, 1992        WHK        Created today                                          }
  687. {                                                                                      }
  688. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  689. FUNCTION AmIAtTurnPoint(carID        : INTEGER)    : BOOLEAN;
  690.     VAR
  691.         aCar    : AutoHandle;
  692.         isThere    : BOOLEAN;
  693.     BEGIN
  694.         AmIAtTurnPoint := FALSE;
  695.         aCar := ReturnCarHandle(carID);
  696.         CASE aCar^^.direction OF
  697.             0:        isThere := (aCar^^.position.h >= gVRoadRight - 10);
  698.             90:        isThere := (aCar^^.position.v <= gHRoadTop + 10);
  699.             180:    isThere := (aCar^^.position.h <= gVRoadLeft +  10);
  700.             270:    isThere := (aCar^^.position.v >= gHRoadBottom - 10);
  701.         END;
  702.         AmIAtTurnPoint := isThere;
  703.     END;
  704.  
  705. {$S Simulation}
  706. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  707. {                                                                                      }
  708. {    CalcCarParams                                                                      }
  709. {                                                                                      }
  710. {    This is where all the magic happens.  This is the preemptive thread that           }
  711. {    calculates the current location of the car in reagrds to other cars and the          }
  712. {    speed and direction that I should be going.  Since this is a preemptive thread,   }
  713. {    it would not be prudent to call any toolbox calls from here.                      }
  714. {                                                                                      }
  715. {    July 15, 1992        WHK        Created today                                          }
  716. {                                                                                      }
  717. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  718. FUNCTION CalcCarParams(theCarRefID    : LONGINT)    : LONGINT;
  719.     VAR
  720.         carLoc                : POINT;
  721.         cardir                : INTEGER;
  722.         madeDecisionToTurn    : BOOLEAN;
  723.         turningRight        : BOOLEAN;
  724.         turningLeft            : BOOLEAN;
  725.         changingLane        : BOOLEAN;
  726.         lastMoveTime        : LONGINT;
  727.         theTime                : LONGINT;
  728.         error                : OSErr;
  729.         hellFreezesOver        : BOOLEAN;
  730.         theCarData            : AutoHandle;
  731.         boundsArea            : RECT;
  732.         direction            : INTEGER;
  733.         myThreadID            : ThreadID;
  734.         turning                : BOOLEAN;
  735.         shiftDist            : INTEGER;
  736.         markedForDeath        : BOOLEAN;
  737.     BEGIN
  738.         madeDecisionToTurn := FALSE;
  739.         changingLane := FALSE;
  740.         boundsArea := WindowPtr(FrontWindow)^.portRect;
  741.         InsetRect(boundsArea, -5, -5);
  742.         
  743.         lastMoveTime := gCurrentTime;    { Could have a problem, but not likely to be a problem!    }
  744.         theCarData := ReturnCarHandle(theCarRefID);
  745.         direction := theCarData^^.direction;
  746.         
  747.         carLoc := theCarData^^.position;
  748.         turning := theCarData^^.turning;
  749.     
  750.         shiftDist := 0;
  751.         
  752.         repeat
  753.             theTime := gCurrentTime;
  754.  
  755.             IF theTime > (lastMoveTime + 4) THEN
  756.                 BEGIN
  757.                     error := ThreadBeginCritical;    { Do not want to redraw the car until I have determined its new location and direction    }
  758.                         IF theCarData^^.speed > 0 THEN
  759.                             BEGIN
  760.                                 CASE direction OF
  761.                                     0:        theCarData^^.position.h := theCarData^^.position.h + 4;
  762.                                     90:        theCarData^^.position.v := theCarData^^.position.v -4;
  763.                                     180:        theCarData^^.position.h := theCarData^^.position.h - 4;
  764.                                     270:        theCarData^^.position.v := theCarData^^.position.v + 4;
  765.                                 END;
  766.                                 
  767.                                 carLoc := theCarData^^.position;
  768.                                 lastMoveTime := theTime;
  769.                                 
  770.                                 IF turning THEN
  771.                                     BEGIN
  772.                                         IF AmIAtTurnPoint(theCarRefID) THEN
  773.                                             BEGIN
  774.                                                 theCarData^^.direction := theCarData^^.direction + 90;
  775.                                                 IF theCarData^^.direction  > 270 THEN
  776.                                                     theCarData^^.direction := 0;
  777.                                                 direction := theCarData^^.direction;
  778.                                                 theCarData^^.recalcCarShape := TRUE;
  779.                                                 turning := FALSE;
  780.                                             END
  781.                                         ELSE IF AmIAtLangeChangePoint(theCarRefID) THEN
  782.                                             BEGIN
  783.                                                 shiftDist := shiftDist + 1;
  784.                                                 IF shiftDist < 11 THEN
  785.                                                     BEGIN
  786.                                                         CASE direction OF
  787.                                                             0:        theCarData^^.position.v := theCarData^^.position.v - 2;
  788.                                                             90:        theCarData^^.position.h := theCarData^^.position.h -2;
  789.                                                             180:    theCarData^^.position.v := theCarData^^.position.v + 2;
  790.                                                             270:    theCarData^^.position.h := theCarData^^.position.h + 2;
  791.                                                         END;
  792.                                                     END;
  793.                                             END;
  794.                                     END;
  795.                                 
  796.                                 theCarData^^.needToRedraw := TRUE;
  797.                                 
  798.                                 IF (IsLightRed(direction) | IsLightArrow(direction))  & AmIAtIntersection(direction, carLoc) THEN
  799.                                     theCarData^^.speed := 0
  800.                                 ELSE IF IsThereACarStoppedInFrontOfMe(carLoc, direction, theCarRefID) THEN
  801.                                     theCarData^^.speed := 0
  802.                                 ELSE IF NOT (IsLightArrow(direction)) & AmIAtIntersection(direction, carLoc) THEN
  803.                                     theCarData^^.speed := 0
  804.                             END
  805.                         ELSE
  806.                             BEGIN
  807.                                 IF (NOT AmIAtIntersection(direction, carLoc))  & (NOT IsThereACarStoppedInFrontOfMe(carLoc, direction, theCarRefID)) THEN
  808.                                     BEGIN
  809.                                         theCarData^^.speed := 40;
  810.                                         lastMoveTime := theTime;
  811.                                     END
  812.                                 ELSE IF (IsLightGreen(direction) & NOT(IsThereACarStoppedInFrontOfMe(carLoc, direction, theCarRefID))) &
  813.                                             ((NOT turning) | (NOT AmIAtLangeChangePoint(theCarRefID))) THEN
  814.                                     BEGIN
  815.                                         theCarData^^.speed := 40;
  816.                                         lastMoveTime := theTime;
  817.                                     END
  818.                                 ELSE IF turning & IsLightArrow(direction) & NOT IsThereACarStoppedInFrontOfMe(carLoc, direction, theCarRefID) THEN
  819.                                     BEGIN
  820.                                         theCarData^^.speed := 40;
  821.                                         lastMoveTime := theTime;
  822.                                     END
  823.                             END;
  824.                     error := ThreadEndCritical;    { Done moving/turning the car, OK for drawing threads to redraw the car now if necessary.    }
  825.                 END;
  826.             error := YieldToAnyThread;    { Not required for pre-emptive threads, but we wish to give up time now to be polite    }
  827.         until CarLeavesPlayingField(carLoc);
  828.         
  829.         error := GetCurrentThread(myThreadID);                { I wish to recycle this thread(possibly), so I need to know my own ID.    }
  830.         
  831.         markedForDeath := theCarData^^.markedForDeath;
  832.         theCarData^^.carIsDone := TRUE;
  833.         
  834.         IF markedForDeath THEN
  835.             error := DisposeThread(myThreadID, 0, FALSE)    { Dispose of myself, do not recycle the threaed into the thread pool.    }
  836.         ELSE
  837.             error := DisposeThread(myThreadID, 0, TRUE);    { Dispose of myself, recycle the threaed into the thread pool.    }
  838.     END;
  839.  
  840. {$S Simulation}
  841. {–––––––––––––––––––––––––––––––––––––COOPERATIVE––––––––––––––––––––––––––––––––––-––}
  842. {                                                                                      }
  843. {    DrawTheTraficLight                                                                  }
  844. {                                                                                      }
  845. {    Now we are at the place that actually draws the traffic light.  Just a lot of      }
  846. {    QuickDraw drawing, so we better not be called from a pre-emptive thread.            }
  847. {                                                                                      }
  848. {    July 15, 1992        WHK        Created today                                          }
  849. {                                                                                      }
  850. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  851. PROCEDURE DrawTheTraficLight(fromThread    : BOOLEAN);
  852.     VAR
  853.         tempRect    : RECT;
  854.         sidePoly    : PolyHandle;
  855.         lightRect    : Rect;
  856.         holdPort    : GrafPtr;
  857.     
  858.     PROCEDURE BlackOutCircle(theCircRect    : RECT);
  859.         BEGIN
  860.             ForeColor(BlackColor);
  861.             FillOval(theCircRect, white)
  862.         END;
  863.         
  864.     BEGIN
  865.         GetPort(holdPort);
  866.         IF fromThread THEN SetPort(gDocument^^.docWindow);
  867.             
  868.         IF NOT(fromThread) THEN
  869.             BEGIN
  870.                 SetRect(tempRect, gVRoadRight + 20, gHRoadTop - 125, gVRoadRight + 50, gHRoadTop - 7);
  871.                 ForeColor(BlackColor);
  872.                 FillRect(tempRect, white);
  873.                 
  874.                 sidePoly := OpenPoly;
  875.                     Moveto(tempRect.left, tempRect.top);
  876.                     Lineto(tempRect.right, tempRect.top);
  877.                     Lineto(tempRect.right  + 35, tempRect.top - 15);
  878.                     Lineto(tempRect.right  + 35, tempRect.bottom - 15);
  879.                     Lineto(tempRect.right, tempRect.bottom);
  880.                     Lineto(tempRect.left, tempRect.bottom);
  881.                     Lineto(tempRect.left, tempRect.top);
  882.                 ClosePoly;
  883.                 FillPoly(sidePoly, white);
  884.                 FramePoly(sidePoly);
  885.                 Moveto(tempRect.right + 1, tempRect.top);
  886.                 Lineto(tempRect.right + 1, tempRect.bottom);
  887.                 
  888.                 KillPoly(sidePoly);
  889.             END;
  890.     
  891.         IF (fromThread AND gTrafficState.dispStateChanged) OR NOT(fromThread) THEN
  892.             BEGIN
  893.                 SetRect(tempRect, gVRoadRight + 20, gHRoadTop - 125, gVRoadRight + 50, gHRoadTop - 7);
  894.  
  895.                 SetRect(lightRect, tempRect.left + 5, tempRect.top + 5, tempRect.right - 5, tempRect.top + 25);
  896.                 BlackOutCircle(lightRect);
  897.                 ForeColor(RedColor);
  898.  
  899.                 IF gTrafficState.lightState IN [0,1,2,3,4] THEN
  900.                     PaintOval(lightRect)
  901.                 ELSE
  902.                     FrameOval(lightRect);
  903.                             
  904.                 SetRect(lightRect, tempRect.left + 5, tempRect.top + 35, tempRect.right - 5, tempRect.top + 55);
  905.                 BlackOutCircle(lightRect);
  906.                 ForeColor(YellowColor);
  907.                 IF gTrafficState.lightState = 7 THEN
  908.                     PaintOval(lightRect)
  909.                 ELSE
  910.                     FrameOval(lightRect);
  911.  
  912.                 SetRect(lightRect, tempRect.left + 5, tempRect.top + 65, tempRect.right - 5, tempRect.top + 85);
  913.                 BlackOutCircle(lightRect);
  914.                 ForeColor(GreenColor);
  915.                 IF gTrafficState.lightState = 6 THEN
  916.                     PaintOval(lightRect)
  917.                 ELSE
  918.                     FrameOval(lightRect);
  919.                     
  920.                 SetRect(lightRect, tempRect.left + 5, tempRect.top + 95, tempRect.right - 5, tempRect.top + 115);
  921.                 BlackOutCircle(lightRect);
  922.                 ForeColor(GreenColor);        { This is for the green Arrow    }
  923.                 FrameOval(lightRect);
  924.                 IF gTrafficState.lightState = 5 THEN
  925.                     BEGIN
  926.                         Moveto(lightRect.left + 3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  927.                         Lineto(lightRect.right - 3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  928.                         Moveto(lightRect.left +7, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2 - 4);
  929.                         Lineto(lightRect.left +3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  930.                         Lineto(lightRect.left +7, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2 + 4);
  931.                     END;
  932.  
  933.                 SetRect(lightRect, tempRect.right + 7, tempRect.top - 2, tempRect.right + 27, tempRect.top + 18);
  934.                 BlackOutCircle(lightRect);
  935.                 ForeColor(RedColor);
  936.                 IF gTrafficState.lightState IN [0,4, 5, 6, 7] THEN
  937.                     PaintOval(lightRect)
  938.                 ELSE
  939.                     FrameOval(lightRect);
  940.                 
  941.                 SetRect(lightRect, tempRect.right + 7, tempRect.top + 28, tempRect.right + 27, tempRect.top + 48);
  942.                 BlackOutCircle(lightRect);
  943.                 ForeColor(YellowColor);
  944.                 IF gTrafficState.lightState = 3 THEN
  945.                     PaintOval(lightRect)
  946.                 ELSE
  947.                     FrameOval(lightRect);
  948.  
  949.                 SetRect(lightRect, tempRect.right + 7, tempRect.top + 58, tempRect.right + 27, tempRect.top + 78);
  950.                 BlackOutCircle(lightRect);
  951.                 ForeColor(GreenColor);
  952.                 IF gTrafficState.lightState = 2 THEN
  953.                     PaintOval(lightRect)
  954.                 ELSE
  955.                     FrameOval(lightRect);
  956.                     
  957.                 SetRect(lightRect, tempRect.right + 7, tempRect.top + 88, tempRect.right + 27, tempRect.top + 108);
  958.                 BlackOutCircle(lightRect);
  959.                 ForeColor(GreenColor);        { This is for the green Arrow    }
  960.                 FrameOval(lightRect);
  961.                 IF gTrafficState.lightState = 1 THEN
  962.                     BEGIN
  963.                         Moveto(lightRect.left + 3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  964.                         Lineto(lightRect.right - 3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  965.                         Moveto(lightRect.left +7, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2 - 4);
  966.                         Lineto(lightRect.left +3, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2);
  967.                         Lineto(lightRect.left +7, lightRect.top + (lightRect.bottom - lightRect.top) DIV 2 + 4);
  968.                     END;
  969.                 gTrafficState.dispStateChanged := FALSE;
  970.             END;
  971.         SetPort(holdPort);
  972.     END;
  973.     
  974. {$S Simulation}
  975. {–––––––––––––––––––––––––––––––––––––COOPERATIVE––––––––––––––––––––––––––––––––––-––}
  976. {                                                                                      }
  977. {    TrafficLightToolboxThread                                                          }
  978. {                                                                                      }
  979. {    This threads purpose is to continually call DrawTheTrafficLight until the end of  }
  980. {    time,  well, at least until the application ends or it gets killed.               }
  981. {    DrawTheTraficLight will    do the determination as to whether it really needs to      }
  982. {    redraw the light or not.                                                          }
  983. {                                                                                      }
  984. {    July 15, 1992        WHK        Created today                                          }
  985. {                                                                                      }
  986. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  987. FUNCTION TrafficLightToolboxThread(threadParam    : LONGINT)    : LONGINT;
  988.     VAR
  989.         error                : OSErr;
  990.     BEGIN
  991.         repeat
  992.             DrawTheTraficLight(TRUE);
  993.             error := YieldToAnyThread;    { Yield to other threads.    }
  994.         until FALSE;
  995.     END;
  996.  
  997. {$S Simulation}
  998. {–––––––––––––––––––––––––––––––––––––COOPERATIVE––––––––––––––––––––––––––––––––––-––}
  999. {                                                                                      }
  1000. {    TimeKeeper                                                                          }
  1001. {                                                                                      }
  1002. {    A cooperative thread, whose only purpose is to stuff a global variable with the   }
  1003. {    value gotten from TickCount.  A lot of pre-emptive threads rely on this data.      }
  1004. {                                                                                      }
  1005. {    July 15, 1992        WHK        Created today                                          }
  1006. {                                                                                      }
  1007. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1008. FUNCTION TimeKeeper(threadParam    : LONGINT)    : LONGINT;
  1009.     VAR
  1010.         error                : OSErr;
  1011.     BEGIN
  1012.         repeat
  1013.             IF TickCount <> gCurrentTime THEN
  1014.                 BEGIN
  1015.                     error := ThreadBeginCritical;    { Make sure other threads cannot access gCurrentTime until I am done changing it.    }
  1016.                     gCurrentTime := TickCount;
  1017.                     error := ThreadEndCritical;        { Done changing it, can be used by other threads now.    }
  1018.                 END;
  1019.             error := YieldToAnyThread; { Yield to other threads. }        
  1020.         until FALSE;
  1021.     END;
  1022.  
  1023. {$S Simulation}
  1024. {–––––––––––––––––––––––––––––––––––––PREEMPTIVE–––––––––––––––––––––––––––––––––––-––}
  1025. {                                                                                      }
  1026. {    TrafficLightCounter                                                                  }
  1027. {                                                                                      }
  1028. {    This is a pre-emptive thread which rotates the light through its various phases.  }
  1029. {    In locations in which global variable structure are shared with other threads and }
  1030. {    could be in a state of flux, I have bracketed them with ThreadBeginCritical/      }
  1031. {    ThreadEndCritical.  It will go on forever, someone else will need to kill it.      }
  1032. {                                                                                      }
  1033. {    July 15, 1992        WHK        Created today                                          }
  1034. {                                                                                      }
  1035. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1036. FUNCTION TrafficLightCounter(threadParam    : LONGINT)    : LONGINT;
  1037.     VAR
  1038.         hellFreezesOver     : BOOLEAN;
  1039.         error                : OSErr;
  1040.         lastTimeSwitch        : LONGINT;
  1041.         currentState        : INTEGER;
  1042.         lightPhaseTimes        : ARRAY[0..3] OF INTEGER;
  1043.         loop                : INTEGER;
  1044.         theTime                : LONGINT;
  1045.     BEGIN
  1046.         FOR loop := 0 TO 3 DO
  1047.             lightPhaseTimes[loop] := gTrafficState.phaseTimes[loop];
  1048.         currentState := gTrafficState.lightState;
  1049.  
  1050.         lastTimeSwitch := gCurrentTime;
  1051.         
  1052.         hellFreezesOver := FALSE;
  1053.         repeat
  1054.             theTime := gCurrentTime;
  1055.  
  1056.             IF theTime > (lastTimeSwitch + (lightPhaseTimes[(currentState MOD 4)]  * 60)) THEN
  1057.                 BEGIN
  1058.                     error := ThreadBeginCritical;    { Do not let traffic light redraw until its state has been completely changed.    }
  1059.                         gTrafficState.lightState := (gTrafficState.lightState + 1) MOD 8;
  1060.                         currentState := gTrafficState.lightState;
  1061.                                                 
  1062.                         gTrafficState.dispStateChanged := TRUE;
  1063.                         lastTimeSwitch := theTime;
  1064.                     error := ThreadEndCritical;        { Done setting new condition, let traffic light be redrawn.    }
  1065.                 END;
  1066.             error := YieldToAnyThread;    { Yield to other threads.    }
  1067.         until hellFreezesOver;
  1068.     END;
  1069.  
  1070. {$S Simulation}
  1071. {––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––––-––}
  1072. {                                                                                      }
  1073. {    InitializeTrafficLightVariables                                                      }
  1074. {                                                                                      }
  1075. {    Initialize the variables that will be manipulate by the traffic light thread.      }
  1076. {                                                                                      }
  1077. {    July 15, 1992        WHK        Created today                                          }
  1078. {                                                                                      }
  1079. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1080. PROCEDURE InitializeTrafficLightVariables;
  1081.     BEGIN
  1082.         gTrafficState.lightState := 0;
  1083.         gTrafficState.phaseTimes[0] := 1;                { Both Red, only occurs for one second        }
  1084.         gTrafficState.phaseTimes[1] := 4;                { Green Arrow, occurs for 8 seconds            }
  1085.         gTrafficState.phaseTimes[2] := 10;                { Solid Green, holds for 20 seconds            }
  1086.         gTrafficState.phaseTimes[3] := 2;                { Yellow light, 3 second hold                }
  1087.         gTrafficState.dispStateChanged := FALSE;        { Do not redraw state, has not yet changed    }
  1088.     END;
  1089.  
  1090. {$S Simulation}
  1091. {––––––––––––––––––––––––––––––––––APPLICATION–––––––––––––––––––––––––––––––––––––-––}
  1092. {                                                                                      }
  1093. {    CreateTrafficLight                                                                  }
  1094. {                                                                                      }
  1095. {    We need to create a traffic light for the intersection before we can run cars      }
  1096. {    through the intersection, think of the mayhem without one.   At the same time I      }
  1097. {    will create a thread for providing time to the pre-emptive threads, which are not }
  1098. {    allowed to call TickCount.                                                          }
  1099. {                                                                                      }
  1100. {    July 15, 1992        WHK        Created today                                          }
  1101. {                                                                                      }
  1102. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1103. PROCEDURE CreateTrafficLight;
  1104.     VAR
  1105.         error            : OSErr;
  1106.         newThreadID    : ThreadID;
  1107.     BEGIN
  1108.         InitializeTrafficLightVariables;
  1109.         gCurrentTime := TickCount;
  1110.         
  1111.         error := CreateThreadPool(kPreemptiveThread, 1, 0);        { Allocate Preemptive threads to the application thread pool.    }
  1112.         IF error <> noErr THEN DebugStr('failure to create asynch thread for the street light');
  1113.  
  1114.         error := CreateThreadPool(kCooperativeThread, 2, 0);    { Allocate Cooperative threads to the application thread pool.    }
  1115.         IF error <> noErr THEN DebugStr('failure to create toolbox thread for the street light');
  1116.         
  1117.         error := NewThread(kCooperativeThread, @TimeKeeper, 0, 0, kUsePremadeThread, NIL, newThreadID);                    { Create new cooperative thread from the pool.    }
  1118.         IF error <> noErr THEN DebugStr('failure to create the thread TimeKeeper');
  1119.  
  1120.         error := NewThread(kCooperativeThread, @TrafficLightToolboxThread, 0, 0, kUsePremadeThread, NIL, newThreadID);    { Create new cooperative thread from the pool.    }
  1121.         IF error <> noErr THEN DebugStr('failure to create the traffic light toolbox thread');
  1122.  
  1123.         error := NewThread(kPreemptiveThread, @TrafficLightCounter, 0, 0, kUsePremadeThread, NIL, newThreadID);            { Create new preemptive thread from the pool.    }
  1124.         IF error <> noErr THEN DebugStr('failure to create traffic light control thread');
  1125.  
  1126.         CreateCarGeneratingThread;
  1127.     END;
  1128.  
  1129. {$S Simulation}
  1130. {–––––––––––––––––––––––––––––PREEMPTIVE–THREADSWITCHER––––––––––––––––––––––––––––-––}
  1131. {                                                                                      }
  1132. {    InDeep                                                                              }
  1133. {                                                                                      }
  1134. {    Quite simple, called only if LoadSeg is called while the current thread is the    }
  1135. {    pre-emptive thread of one of the cars.                                            }
  1136. {                                                                                      }
  1137. {    July 15, 1992        WHK        Created today                                          }
  1138. {                                                                                      }
  1139. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1140. PROCEDURE InDeep;
  1141.     BEGIN
  1142.         DebugStr('Hey, no LoadSeg Calls allowed here!!!!!');
  1143.     END;
  1144.  
  1145. {$S Simulation}
  1146. {–––––––––––––––––––––––––––––PREEMPTIVE–THREADSWITCHER––––––––––––––––––––––––––––-––}
  1147. {                                                                                      }
  1148. {    SwitcherInner                                                                      }
  1149. {                                                                                      }
  1150. {    In a pre-emptive thread, it would be bad to call LoadSeg.  This Switcher was set  }
  1151. {    up to patch LoadSeg and replace it with my call in case LoadSeg was called          }
  1152. {    anytime within the cars pre-emptive thread.  If InDeep is ever executed, you are  }
  1153. {    already in bad shape.                                                               }
  1154. {                                                                                      }
  1155. {    Note: There are many other calls that should not be done from a pre-emptive          }
  1156. {    thread.                                                                              }
  1157. {                                                                                      }
  1158. {    July 15, 1992            Created by William Knott                                  }
  1159. {                                                                                      }
  1160. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1161. PROCEDURE SwitcherInner(threadID    : ThreadID;
  1162.                             data    : LONGINT);
  1163.     VAR
  1164.         aCar    : AutoHandle;
  1165.     BEGIN
  1166.         aCar := ReturnCarHandle(data);
  1167.         IF aCar <> NIL THEN
  1168.             BEGIN
  1169.                 aCar^^.oldTrapAddr := Handle(GetTrapAddress(_LoadSeg));
  1170.                 SetTrapAddress(LONGINT(@InDeep), _LoadSeg);
  1171.             END;
  1172.     END;
  1173.  
  1174. {$S Simulation}
  1175. {–––––––––––––––––––––––––––––PREEMPTIVE–THREADSWITCHER––––––––––––––––––––––––––––-––}
  1176. {                                                                                      }
  1177. {    SwitcherOuter                                                                      }
  1178. {                                                                                      }
  1179. {    SwitcherInner caused LoadSeg to get patched with my routine, we need to restore   }
  1180. {    the LoadSeg trap address.                                                          }
  1181. {                                                                                      }
  1182. {    July 15, 1992        WHK        Created today                                          }
  1183. {                                                                                      }
  1184. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1185. PROCEDURE SwitcherOuter(threadID    : ThreadID;
  1186.                             data    : LONGINT);
  1187.     VAR
  1188.         aCar    : AutoHandle;
  1189.     BEGIN
  1190.         aCar := ReturnCarHandle(data);
  1191.         IF aCar <> NIL THEN
  1192.             BEGIN
  1193.                 IF aCar^^.oldTrapAddr <> NIL THEN
  1194.                     SetTrapAddress(LONGINT(aCar^^.oldTrapAddr), _LoadSeg);
  1195.             END;
  1196.     END;
  1197.  
  1198. {$S Simulation}
  1199. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1200. {                                                                                      }
  1201. {    AddACarToTheRoad                                                                  }
  1202. {                                                                                      }
  1203. {    In generating new cars, we have determined that are at least two free threads,      }
  1204. {    one of type cooperative, and one of type pre-emptive.  We first create a new car  }
  1205. {    in the car list so that we can pass a reference to it to both threads required to }
  1206. {    make a car go.  We will also be setting routines that will be called whenever the }
  1207. {    cars pre-emptive threads are switched into or out of.  If there is no free place  }
  1208. {    on the board for a new car, then we will not create one for now.                  }
  1209. {                                                                                      }
  1210. {    July 15, 1992        WHK        Created today                                          }
  1211. {                                                                                      }
  1212. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1213. PROCEDURE AddACarToTheRoad;
  1214.     VAR
  1215.         error            : OSErr;
  1216.         uniqueCarID        : INTEGER;
  1217.         newThreadID        : ThreadID;
  1218.         aCar            : AutoHandle;
  1219.         positionBogus    : BOOLEAN;
  1220.     BEGIN
  1221.         uniqueCarID := GetUniqueCarID;
  1222.         CreateANewAutomobile(uniqueCarID);
  1223.         
  1224.         aCar := ReturnCarHandle(uniqueCarID);
  1225.         
  1226.         positionBogus := AmIOnTopOfACar(aCar^^.position, aCar^^.direction, uniqueCarID);
  1227.  
  1228.         IF NOT positionBogus THEN
  1229.             BEGIN
  1230.                 error := NewThread(kPreemptiveThread, @CalcCarParams, uniqueCarID, 0, kUsePremadeThread + kNewSuspend, NIL, newThreadID);    { Create a new thread from the application        }
  1231.                                                                                                                                             { thread pool and set its state to suspended.    }
  1232.                 IF error <> noErr THEN
  1233.                     DebugStr('Failure to create car position calculating thread')
  1234.                 ELSE
  1235.                     BEGIN
  1236.                         error := SetThreadSwitcher (newThreadID, ThreadSwitchProcPtr(@SwitcherInner), uniqueCarID, TRUE);    { Set the procedure SwitcherInner to be called whenever    }
  1237.                                                                                                                             { we switch into this preemptive thread.                }
  1238.                         IF error <> noErr THEN DebugStr('failure to set innie');
  1239.  
  1240.                         error := SetThreadSwitcher (newThreadID, ThreadSwitchProcPtr(@SwitcherOuter), uniqueCarID, FALSE);    { Set the procedure SwitcherOuter to be called whenever    }
  1241.                                                                                                                             { we switch out of this preemptive thread.                }
  1242.                         IF error <> noErr THEN DebugStr('failure to set outie');                
  1243.                     END;
  1244.         
  1245.                 error := SetThreadState (newThreadID, kReadyThreadState, kNoThreadID);
  1246.         
  1247.                 error := NewThread(kCooperativeThread, @CarDrawingThread, uniqueCarID, 0, kUsePremadeThread, NIL, newThreadID);    { Create a preemptive thread from the application    }
  1248.                                                                                                                                 { for drawing the car on the road.                    }
  1249.                 IF error <> noErr THEN DebugStr('failure to create traffic light drawing thread');
  1250.             END
  1251.         ELSE
  1252.             BEGIN
  1253.                 DisposHandle(Handle(gAutomobiles^^[uniqueCarID]));
  1254.                 gAutomobiles^^[uniqueCarID] := NIL;
  1255.             END;
  1256.     END;
  1257.  
  1258. {$S Simulation}
  1259. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1260. {                                                                                      }
  1261. {    GenerateNewCarsThread                                                              }
  1262. {                                                                                      }
  1263. {    This Threads responsibility is initially add four cars to the road, then to           }
  1264. {    continually check to see if there is a free thread in the cooperative thread      }
  1265. {    pool, and a free thread in the pre-emptive thread pool.  If so, we have what is      }
  1266. {    needed for a car, so lets create it.  Since this is a cooperative thread, we need }
  1267. {    to explicitally yield to other threads.                                              }
  1268. {                                                                                      }
  1269. {    July 15, 1992        WHK        Created today                                          }
  1270. {                                                                                      }
  1271. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1272. FUNCTION GenerateNewCarsThread(threadParam    : LONGINT)    : LONGINT;
  1273.     VAR
  1274.         error                : OSErr;
  1275.         newThreadID            : ThreadID;
  1276.         numAsyncFree        : INTEGER;
  1277.         numToolboxFree        : INTEGER;
  1278.     BEGIN
  1279.         repeat
  1280.             error := GetFreeThreadCount(kPreemptiveThread, numAsyncFree);            { Get the count of the number of free preemptive threads in  application pool    }
  1281.             error := GetFreeThreadCount(kCooperativeThread, numToolboxFree);        { Get the count of the number of free cooperative threads in  application pool    }
  1282.  
  1283.             IF (numAsyncFree > 0) AND (numToolboxFree > 0) THEN
  1284.                 AddACarToTheRoad;
  1285.             error := YieldToAnyThread;    { Yield to other threads.    }
  1286.         until HellFreezesOver;
  1287.     END;
  1288.  
  1289. {$S Simulation}
  1290. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1291. {                                                                                      }
  1292. {    DisposeThreadsFromPool                                                              }
  1293. {                                                                                      }
  1294. {    When I am generating a new Car generating thread I run into the problem that I      }
  1295. {    may allocated 5 cooperative threads then fail to allocate 4 pre-emptive threads.  }
  1296. {    This would be a real bummer in terms of memory so it would be nice if I could      }
  1297. {    get rid of threads in the thread pool if I do not want them.                      }
  1298. {                                                                                      }
  1299. {    July 15, 1992        WHK        Created today                                          }
  1300. {                                                                                      }
  1301. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1302. FUNCTION DisposeThreadsFromPool(threadStyle        : ThreadStyle;
  1303.                                     howMany        : INTEGER)    : OSErr;
  1304.     VAR
  1305.         newThreadID    : ThreadID;
  1306.         error            : OSErr;
  1307.         loop            : INTEGER;
  1308.     BEGIN
  1309.         DisposeThreadsFromPool := noErr;
  1310.         FOR loop := 1 TO howMany DO
  1311.             BEGIN
  1312.                 error := NewThread(threadStyle, @DisposeThreadsFromPool, 0, 0, kUsePremadeThread + kNewSuspend, NIL, newThreadID);    { Create a new thread from the application thread    }
  1313.                                                                                                                                     { pool, its initial state is suspended.                }
  1314.                 IF error <> noErr THEN LEAVE;
  1315.                 error := DisposeThread(newThreadID, 0, FALSE);    { Dispose of a thread, do not recycle it into the application thread pool.    }
  1316.                 
  1317.                 
  1318.                 IF error <> noErr THEN LEAVE;
  1319.             END;
  1320.         DisposeThreadsFromPool := error;
  1321.     END;
  1322.  
  1323. {$S Simulation}
  1324. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1325. {                                                                                      }
  1326. {    CreateFreeThreadsForCars                                                          }
  1327. {                                                                                      }
  1328. {    We need to create more threads so that more cars can be added to the road.          }
  1329. {    Create four cooperative and four pre-emptive threads for use in the traffic          }
  1330. {    simulation.                                                                        }
  1331. {                                                                                      }
  1332. {    July 15, 1992        WHK        Created today                                          }
  1333. {                                                                                      }
  1334. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1335. PROCEDURE CreateFreeThreadsForCars;
  1336.     VAR
  1337.         error            : OSErr;
  1338.         newThreadID    : ThreadID;
  1339.     BEGIN
  1340.         error := CreateThreadPool(kCooperativeThread, 4, 0);                    { Allocate four cooperative threads into the applications thread pool.    }
  1341.             IF error = noErr THEN
  1342.                 BEGIN
  1343.                     error := CreateThreadPool(kPreemptiveThread, 4, 0);            { Allocate four preemptive threads into the applications thread pool.    }
  1344.                     IF error <> noErr THEN
  1345.                         BEGIN
  1346.                             error := DisposeThreadsFromPool(kCooperativeThread, 5);
  1347.                             Sysbeep(1);
  1348.                         END;
  1349.                 END
  1350.             ELSE
  1351.                 Sysbeep(1);
  1352.     END;
  1353.  
  1354. {$S Simulation}
  1355. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1356. {                                                                                      }
  1357. {    CreateCarGeneratingThread                                                          }
  1358. {                                                                                      }
  1359. {    We need to create the thread that actually gets all the cars moving on the road.  }
  1360. {    Simply create and set running a cooperative thread.                                  }
  1361. {                                                                                      }
  1362. {    July 15, 1992        WHK        Created today                                          }
  1363. {                                                                                      }
  1364. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1365. PROCEDURE CreateCarGeneratingThread;
  1366.     VAR
  1367.         error            : OSErr;
  1368.         newThreadID    : ThreadID;
  1369.     BEGIN
  1370.         error := CreateThreadPool(kCooperativeThread, 1, 0);        { Allocate a cooperative threads into the applications thread pool.    }
  1371.         IF error <> noErr THEN
  1372.             DebugStr('Failure to create car utiliation thread')
  1373.         ELSE
  1374.             error := NewThread(kCooperativeThread, @GenerateNewCarsThread, 0, 0, kUsePremadeThread, NIL, newThreadID);        { Create a new thread from the exisiting thread pool.    }
  1375.     END;
  1376.  
  1377. {$S Simulation}
  1378. {––––––––––––––––––––––––––––––––––––COOPERATIVE–––––––––––––––––––––––––––––––––––-––}
  1379. {                                                                                      }
  1380. {    MarkACarForDestruction                                                              }
  1381. {                                                                                      }
  1382. {    The user wishes for a car to be removed from the road.  The easiest time to do      }
  1383. {    this is when the car leaves the road and is normally requeued for another  run      }
  1384. {    down the road. Set the carType to 5 so that the car will appear white and          }
  1385. {    needToRedraw to TRUE so that even stopped cars will be redrawn.                      }
  1386. {                                                                                      }
  1387. {    July 16, 1992        WHK        Created today                                          }
  1388. {                                                                                      }
  1389. {––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––-––}
  1390. PROCEDURE MarkACarForDestruction;
  1391.     VAR
  1392.         loop    : INTEGER;
  1393.         theCar    : AutoHandle;
  1394.     BEGIN
  1395.         IF gAutomobiles = NIL THEN
  1396.             BEGIN
  1397.                 Sysbeep(1);
  1398.                 EXIT(MarkACarForDestruction);
  1399.             END;
  1400.         
  1401.         FOR loop := 1 TO gTotalCarsInArray DO
  1402.             BEGIN
  1403.                 theCar := ReturnCarHandle(loop);
  1404.                 IF theCar <> NIL THEN
  1405.                     BEGIN
  1406.                         IF NOT(theCar^^.markedForDeath) THEN
  1407.                             BEGIN
  1408.                                 theCar^^.markedForDeath := TRUE;
  1409.                                 theCar^^.carType := 5;
  1410.                                 theCar^^.needToRedraw := TRUE;
  1411.                                 LEAVE;
  1412.                             END
  1413.                     END;
  1414.             END;
  1415.     END;
  1416.  
  1417. END.